import * as fs from 'fs';
import path from 'path';
import * as vscode from 'vscode';
import Logger from './log';

interface MsgType {
    type: string,
    params: string
}

class WebviewMgr {
    private static instance: WebviewMgr | null = null;
    private panel: vscode.WebviewPanel | null = null;
    private context: vscode.ExtensionContext | null = null;
    private webRootPath: string | null = null;
    private handlers: Map<string, (e: MsgType)=>void>;

    private constructor() {
        this.handlers = new Map<string, (e: MsgType)=>void>();
    }

    public static GetInstance(): WebviewMgr {
        if (!WebviewMgr.instance) {
            WebviewMgr.instance = new WebviewMgr();
        }
        return WebviewMgr.instance;
    }

    public Initialize(context: vscode.ExtensionContext, webRootPath: string): void {
        this.context = context;
        this.webRootPath = path.join(this.context.extensionPath, webRootPath);
    }

    public ShowWebView(htmlPath: string): boolean {
        if (!this.context || !this.webRootPath) {
            Logger.Error(`The context or webRootPath is null.`);
            return false;
        }
        if (!this.panel) {
            this.panel = vscode.window.createWebviewPanel(
                'auto_tools', // viewType
                "Auto Tools", // 视图标题
                vscode.ViewColumn.Active, // 显示在编辑器的哪个部位
                {
                    enableScripts: true, // 启用JS，默认禁用
                    localResourceRoots: [vscode.Uri.file(this.webRootPath)]
                }
            );
            // 当面板关闭时，清除引用
            this.panel.onDidDispose(
                () => {
                    this.panel = null;
                },
                null,
                this.context.subscriptions
            );
            this.panel.webview.onDidReceiveMessage(
                async (message: { type: string, params: string }) => {
                    this.ProcessMessages(message);
                },
                undefined,
                this.context!.subscriptions
            );
        }

        let htmlContent = fs.readFileSync(path.join(this.webRootPath, htmlPath), 'utf-8');

        // vscode不支持直接加载本地资源，需要替换成其专有路径格式
        htmlContent = htmlContent.replace(/(<link.+?href="|<script.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {
            const tmpUri = this.panel!.webview.asWebviewUri(
                vscode.Uri.file(path.join(this.webRootPath!, $2))
            );
            return $1 + tmpUri + '"';
        });

        this.panel.webview.html = htmlContent;
        return true;
    }

    public RegisterHandler(type: string, handler: (e: MsgType)=>void) {
        this.handlers.set(type, handler);
    }

    private ProcessMessages(message: MsgType) {
        if (!message.type || !message.params) {
            Logger.Error(`The message "${JSON.stringify(message)}" from web does not have a "type" or "params" property.`);
            return;
        }
        Logger.Info(`The message from web view is: ${JSON.stringify(message)}.`);
        const handler = this.handlers.get(message.type);
        if (handler) {
            handler(message);
        }
    }

    public Send(message: MsgType) {
        if (!this.panel) {
            Logger.Error(`The webview is not initialized, and the message "${JSON.stringify(message)}" is send failed.`);
            return;
        }
        this.panel.webview.postMessage(message);
    }
}

export default WebviewMgr;